// 确保Adafruit_PN532库明确使用SPI模式而非I2C模式
#include <pins.h>

#include <WiFi.h>
#include <HTTPClient.h>
#include <Audio.h>  // ESP32-audioI2S库
#include <Adafruit_PN532.h>  // PN532库
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>
#include <ArduinoJson.h>  // 用于解析JSON响应
#include <lcd/lcd_demo.h>

// LVGL相关头文件
#include <lv_conf.h>
#include <lvgl.h>
#include <lvgl_init.h>
#include <lvgl_driver.h>
#include <lvgl_app.h>

// 创建PN532实例 - 使用SPI
Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);
// 创建音频实例
Audio audio;

// WiFi配置
const char* ssid = "DX2.4";
const char* password = "bs666666";

// 当前播放的歌曲URL
const char* currentStreamUrl = "";

// LVGL定时器句柄
static TimerHandle_t lvglTickTimer = NULL;

// PN532模块版本数据（全局变量，用于检测模块连接状态）
uint32_t versiondata = 0;

// 歌曲映射表：卡片ID -> 歌曲URL
struct SongMap {
  String cardId;
  const char* songUrl;
  const char* songName;
};

// 定义卡片ID和对应歌曲的映射
SongMap songMap[] = {
  {"53:25:4E:F7:32:00:01", "http://music.163.com/song/media/outer/url?id=1330348068.mp3", "起风了"},
  {"53:53:6A:F7:32:00:01", "http://music.163.com/song/media/outer/url?id=1962556941.mp3", "无羁"},
  {"53:09:8B:F7:32:00:01", "http://music.163.com/song/media/outer/url?id=569214252.mp3", "如果有一天我变得很有钱"}
};

// API配置 - 修改为用户提供的API地址格式
const char* API_ENDPOINT = "http://192.168.3.15:8001/api/rfid";
const char* API_ENDPOINT_SUFFIX = "/audio-url";

// 添加日志宏保持代码简洁
#define LOG(msg) Serial.printf("[%5lu ms] %s\n", millis(), msg)
#define LOG_F(format, ...) Serial.printf("[%5lu ms] " format, millis(), ##__VA_ARGS__)

// 启动电机
void startMotor() {
  digitalWrite(IN1_PIN, HIGH);
  digitalWrite(IN2_PIN, LOW);
  analogWrite(ENA_PIN, MOTOR_SPEED);
  LOG("电机已启动");
}

// 停止电机
void stopMotor() {
  digitalWrite(ENA_PIN, LOW);
  digitalWrite(IN1_PIN, LOW);
  digitalWrite(IN2_PIN, LOW);
  LOG("电机已停止");
}

// 播放指定URL的歌曲
void playSong(const char* url, const char* songName) {
  // 如果已经在播放相同的歌曲，则不做处理
  if (strcmp(currentStreamUrl, url) == 0) {
    return;
  }

  // 停止当前播放
  audio.stopSong();
  stopMotor();  // 停止电机
  delay(500);

  // 播放新歌曲
  LOG_F("播放歌曲");
  LOG_F("连接到音频流: %s", url);
  audio.connecttohost(url);
  currentStreamUrl = url;
  
  // 启动电机
  startMotor();
}

// 将PN532读取的UID转换为格式化的十六进制字符串，如 53:25:4E:F7:32:00:01
String getCardId(uint8_t* uid, uint8_t uidLength) {
  String cardId = "";
  for (uint8_t i = 0; i < uidLength; i++) {
    if (i > 0) {
      cardId += ":";
    }
    // 确保每个字节显示为两位十六进制数
    if (uid[i] < 0x10) {
      cardId += "0";
    }
    cardId += String(uid[i], HEX);
  }
  cardId.toUpperCase();
  return cardId;
}

// 向API发送卡片ID并获取歌曲信息
bool fetchSongFromAPI(String cardId, String &songUrl, String &songName) {
  HTTPClient http;
  // 构建符合用户提供的API地址格式: http://localhost:8000/api/rfid/卡片ID/audio-url
  String apiUrl = String(API_ENDPOINT) + "/" + cardId + API_ENDPOINT_SUFFIX;
  
  LOG_F("向API请求歌曲信息: %s", apiUrl.c_str());
  
  http.begin(apiUrl);
  int httpCode = http.GET();
  
  if (httpCode > 0) {
    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      LOG_F("API响应: %s", payload.c_str());
      
      // 解析JSON响应 - 适配用户提供的格式 {"audio_url": "..."}
      StaticJsonDocument<200> doc;
      DeserializationError error = deserializeJson(doc, payload);
      
      if (!error) {
        if (doc.containsKey("audio_url")) {
          songUrl = doc["audio_url"].as<String>();
          // API没有返回歌曲名称，使用默认名称或URL的一部分作为歌曲名
          songName = "从API获取的歌曲";
          http.end();
          return true;
        } else {
          LOG("API响应中不包含audio_url字段");
        }
      } else {
        LOG_F("JSON解析错误: %s", error.c_str());
      }
    } else {
      LOG_F("API请求失败，HTTP代码: %d", httpCode);
    }
  } else {
    LOG_F("API连接失败: %s", http.errorToString(httpCode).c_str());
  }
  
  http.end();
  return false;
}

// 音频处理任务函数
void audioTask(void *pvParameters) {
  LOG("音频处理任务已启动");
  
  while (true) {
    // 持续调用audio.loop()以处理音频数据
    audio.loop();
    
    // 添加一个小延迟，让出一些CPU时间，但不要太长影响音频流畅度
    vTaskDelay(1 / portTICK_PERIOD_MS);
  }
}

// LVGL定时器回调函数，用于更新LVGL的tick
void lvglTickTimerCallback(TimerHandle_t xTimer) {
  lvgl_tick_handler();
}

// 检查音频播放状态的函数
void checkAudioStatus() {
  static bool wasPlaying = false;
  
  // 检查当前是否在播放音频
  bool isPlaying = (audio.isRunning() != 0);
  
  // 如果状态发生变化
  if (wasPlaying != isPlaying) {
    if (isPlaying) {
      LOG("音频开始播放");
      startMotor();  // 开始播放时启动电机
    } else {
      LOG("音频停止播放");
      stopMotor();  // 停止播放时停止电机
    }
    wasPlaying = isPlaying;
  }
}

void setup() {
  Serial.begin(9600);
  LOG("音频播放器初始化中...");
  
  // 初始化LVGL
  LOG("初始化LVGL图形库...");
  lvgl_init();
  
  // 创建LVGL tick定时器，每1ms更新一次
  lvglTickTimer = xTimerCreate(
    "lvglTick",                 // 定时器名称
    pdMS_TO_TICKS(1),           // 定时器周期，1ms
    pdTRUE,                     // 自动重载
    NULL,                       // 定时器ID
    lvglTickTimerCallback       // 回调函数
  );
  
  // 启动定时器
  xTimerStart(lvglTickTimer, 0);
  
  // 初始化LVGL应用界面
  LOG("初始化LVGL应用界面...");
  lvgl_app_init();
  
  // 不再使用LCD_DEMO()，因为我们将使用LVGL
  LOG("LVGL初始化完成");
  LOG("LVGL应用界面初始化完成");
  // 初始化电机控制引脚
  pinMode(IN1_PIN, OUTPUT);
  pinMode(IN2_PIN, OUTPUT);
  pinMode(ENA_PIN, OUTPUT);
  stopMotor();  // 初始状态为停止

  // 初始化PN532模块
  nfc.begin();
  
  // 检查PN532是否正常连接
  versiondata = nfc.getFirmwareVersion();
  if (!versiondata) {
    LOG("! 未找到PN532模块，请检查连接");
    LOG("! 系统将继续运行，但NFC功能将不可用");
    // 不进入无限循环，而是继续执行其他功能
    // 可以在后续代码中通过versiondata为0来判断NFC模块状态
  }
  
  // 显示PN532信息
  LOG_F("找到PN532芯片，固件版本: %#08x", versiondata);
  
  // 配置PN532以读取NFC卡片
  nfc.SAMConfig();
  LOG("PN532模块初始化完成");
  LOG("请将NFC卡片靠近读卡器...");

  // WiFi 连接流程
  LOG("正在连接WiFi...");
  Serial.printf("- SSID: %s\n", ssid);

  WiFi.begin(ssid, password);

  unsigned long startTime = millis();
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    // 10秒后超时
    if (millis() - startTime > 10000) {
      LOG("! WiFi连接超时");
      ESP.restart();
    }
  }

  LOG_F("WiFi连接成功! IP: %s, RSSI: %ddBm", 
        WiFi.localIP().toString().c_str(), WiFi.RSSI());

  // 音频硬件配置
  LOG("配置I2S音频...");
  // Audio::setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t DIN = -1, int8_t MCK = -1)
  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  audio.setVolume(15); // 0-21范围，设置音量

  // 创建音频处理任务，在核心1上运行，增加栈大小到8192字节以避免堆栈溢出
  xTaskCreatePinnedToCore(
    audioTask,     // 任务函数
    "audioTask",   // 任务名称
    8192,          // 任务栈大小，从4096增加到8192以防止堆栈溢出
    NULL,          // 任务参数
    5,             // 任务优先级
    NULL,          // 任务句柄
    1              // 运行在核心1
  );

  LOG("初始化完成!");
}

// 添加变量来跟踪卡片状态
unsigned long lastCardDetectedTime = 0;
String currentCardId = "";
int cardAbsenceCount = 0; // 连续检测不到卡片的次数计数器
const unsigned long STATUS_CHECK_INTERVAL = 200; // 状态检查间隔（毫秒）
const int CARD_ABSENCE_THRESHOLD = 10; // 连续检测不到卡片的次数阈值，达到后停止播放

void loop() {
  // 检查是否有新卡片
  uint8_t success = false; // 操作结果
  uint8_t uid[8];  // 存储UID
  uint8_t uidLength; // UID长度
  unsigned long currentTime = millis();
  
  // 只有当PN532模块正常连接时才尝试读取卡片
  if (versiondata) {
    // 等待检测到ISO14443A类型的卡片（Mifare等）
    success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 50); // 减小等待时间以提高响应速度
  }
  
  // 定期检查音频播放状态，无论是否检测到卡片
  if (currentTime - lastCardDetectedTime > STATUS_CHECK_INTERVAL) {
    checkAudioStatus();
  }
  
  // 查找对应歌曲
  if (success) {
    lastCardDetectedTime = currentTime;
    String cardId = getCardId(uid, uidLength);
    cardAbsenceCount = 0;
    // 只有在检测到新卡片或者距离上次检测时间超过指定间隔时才处理
    if (cardId != currentCardId) {
      LOG_F("检测到卡片: %s", cardId.c_str());
      bool found = false;
      for (int i = 0; i < sizeof(songMap) / sizeof(songMap[0]); i++) {
        if (songMap[i].cardId.equals(cardId)) {
          playSong(songMap[i].songUrl, songMap[i].songName);
          found = true;
          break;
        }
      }
      
      if (!found) {
        LOG_F("未找到卡片 %s 对应的歌曲", cardId.c_str());
      }
      // 更新当前卡片ID和最后检测时间
      currentCardId = cardId;
    }
  } else {
    // 未检测到卡片，增加计数器
    if (currentCardId != "") {
      cardAbsenceCount++;
      LOG_F("未检测到卡片，连续次数: %d/%d", cardAbsenceCount, CARD_ABSENCE_THRESHOLD);
      
      // 检查是否达到阈值
      if (cardAbsenceCount >= CARD_ABSENCE_THRESHOLD) {
        // 连续检测不到卡片达到阈值，停止播放
        LOG("连续多次未检测到卡片，停止播放");
        audio.stopSong();
        stopMotor();
        currentCardId = "";
        currentStreamUrl = "";
        cardAbsenceCount = 0; // 重置计数器
      }
    }
  }
  
  // 当检测到卡片时，重置计数器
  if (success && currentCardId != "") {
    cardAbsenceCount = 0;
  }
  
  // 小延迟以避免CPU过度占用
  delay(5);



  // if (success) {
  //   // 获取卡片ID
  //   String cardId = getCardId(uid, uidLength);
  //   LOG_F("检测到卡片: %s", cardId.c_str());

  //   // 从API获取歌曲信息
  //   String songUrl = "";
  //   String songName = "";
    
  //   if (fetchSongFromAPI(cardId, songUrl, songName)) {
  //     // 将String转换为const char*以便传递给playSong函数
  //     playSong(songUrl.c_str(), songName.c_str());
  //   } else {
  //     LOG_F("未找到卡片 %s 对应的歌曲", cardId.c_str());
  //   }
    
  //   // 短暂延迟以防止重复读取
  //   delay(1000);
  // } else {
  //   // 定期检查音频播放状态
  //   checkAudioStatus();
  //   delay(10); // 减小延迟以提高响应速度
  // }

  // 每10秒报告一次状态
  static unsigned long lastReport = 0;
  if (millis() - lastReport > 10000) {
    LOG_F("状态: 播放时间 %d 秒, 空闲内存: %d 字节", 
          millis() / 1000, ESP.getFreeHeap());
    lastReport = millis();
  }
  
  // 调用LVGL任务处理函数，处理UI更新
  lvgl_task_handler();
}